name = "cargo-generate-lockfile"
test = false
+[[bin]]
+name = "cargo-update"
+test = false
+
[[test]]
name = "tests"
-j N, --jobs N The number of jobs to run in parallel
--release Build artifacts in release mode, with optimizations
--target TRIPLE Build for the target triple
- -u, --update-remotes Update all remote packages before compiling
+ -u, --update-remotes Deprecated option, use `cargo update` instead
--manifest-path PATH Path to the manifest to compile
-v, --verbose Use verbose output
", flag_jobs: Option<uint>, flag_target: Option<String>,
-h, --help Print this message
--no-deps Don't build documentation for dependencies
-j N, --jobs N The number of jobs to run in parallel
- -u, --update-remotes Update all remote packages before compiling
+ -u, --update-remotes Deprecated option, use `cargo update` instead
--manifest-path PATH Path to the manifest to document
-v, --verbose Use verbose output
Options:
-h, --help Print this message
-j N, --jobs N The number of jobs to run in parallel
- -u, --update-remotes Update all remote packages before compiling
+ -u, --update-remotes Deprecated option, use `cargo update` instead
--manifest-path PATH Path to the manifest to execute
-v, --verbose Use verbose output
Options:
-h, --help Print this message
-j N, --jobs N The number of jobs to run in parallel
- -u, --update-remotes Update all remote packages before compiling
+ -u, --update-remotes Deprecated option, use `cargo update` instead
--manifest-path PATH Path to the manifest to build tests for
-v, --verbose Use verbose output
--- /dev/null
+#![feature(phase)]
+
+extern crate serialize;
+extern crate cargo;
+extern crate docopt;
+#[phase(plugin)] extern crate docopt_macros;
+#[phase(plugin, link)] extern crate log;
+
+use std::os;
+use cargo::ops;
+use cargo::{execute_main_without_stdin};
+use cargo::core::MultiShell;
+use cargo::util::{CliResult, CliError};
+use cargo::util::important_paths::find_root_manifest_for_cwd;
+
+docopt!(Options, "
+Update dependencies as recorded in the local lock file.
+
+Usage:
+ cargo-update [options] [<name>]
+
+Options:
+ -h, --help Print this message
+ --manifest-path PATH Path to the manifest to compile
+ -v, --verbose Use verbose output
+
+This command requires that a `Cargo.lock` already exists as generated by
+`cargo build` or related commands.
+
+If <name> is specified, then a conservative update of the lockfile will be
+performed. This means that only the dependency <name> (and all of its transitive
+dependencies) will be updated. All other dependencies will remain locked at
+their currently recorded versions.
+
+If <name> is not specified, then all dependencies will be re-resolved and
+updated.
+", flag_manifest_path: Option<String>, arg_name: Option<String>)
+
+fn main() {
+ execute_main_without_stdin(execute, false);
+}
+
+fn execute(options: Options, shell: &mut MultiShell) -> CliResult<Option<()>> {
+ debug!("executing; cmd=cargo-update; args={}", os::args());
+ shell.set_verbose(options.flag_verbose);
+ let root = try!(find_root_manifest_for_cwd(options.flag_manifest_path));
+
+ ops::update_lockfile(&root, shell, options.arg_name)
+ .map(|_| None).map_err(|err| CliError::from_boxed(err, 101))
+}
+
new Create a new cargo project
run Build and execute src/main.rs
test Run the tests
+ update Update dependencies listed in Cargo.lock
See 'cargo help <command>' for more information on a specific command.
")
use std::os;
use std::collections::HashMap;
-use std::io::File;
-use serialize::Decodable;
-use rstoml = toml;
use core::registry::PackageRegistry;
-use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId, Resolve, resolver};
+use core::{MultiShell, Source, SourceId, PackageSet, Target, PackageId};
+use core::resolver;
use ops;
use sources::{PathSource};
use util::config::{Config, ConfigValue};
-use util::{CargoResult, Wrap, config, internal, human, ChainError, toml};
+use util::{CargoResult, Wrap, config, internal, human, ChainError};
use util::profile;
pub struct CompileOptions<'a> {
log!(4, "compile; manifest-path={}", manifest_path.display());
+ if options.update {
+ return Err(human("The -u flag has been deprecated, please use the \
+ `cargo update` command instead"));
+ }
+
let mut source = PathSource::for_path(&manifest_path.dir_path());
try!(source.update());
let mut registry = PackageRegistry::new(&mut config);
- let resolved = match try!(load_lockfile(&lockfile, source_id)) {
+ let resolved = match try!(ops::load_lockfile(&lockfile, source_id)) {
Some(r) => {
try!(registry.add_sources(r.iter().map(|p| {
p.get_source_id().clone()
Ok(test_executables)
}
-fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
- // If there is no lockfile, return none.
- let mut f = match File::open(path) {
- Ok(f) => f,
- Err(_) => return Ok(None)
- };
-
- let s = try!(f.read_to_string());
-
- let table = rstoml::Table(try!(toml::parse(s.as_slice(), path)));
- let mut d = rstoml::Decoder::new(table);
- let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
- Ok(Some(try!(v.to_resolve(sid))))
-}
-
fn source_ids_from_config(configs: &HashMap<String, config::ConfigValue>,
cur_path: Path) -> CargoResult<Vec<SourceId>> {
debug!("loaded config; configs={}", configs);
+#![warn(warnings)]
+use std::collections::HashSet;
use std::io::File;
-use serialize::Encodable;
-use toml::{mod, Encoder};
+use serialize::{Encodable, Decodable};
+use toml::Encoder;
+use rstoml = toml;
use core::registry::PackageRegistry;
-use core::{MultiShell, Source, Resolve, resolver, Package};
+use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
+use core::PackageId;
use sources::{PathSource};
use util::config::{Config};
-use util::{CargoResult};
+use util::{CargoResult, toml, human};
pub fn generate_lockfile(manifest_path: &Path,
shell: &mut MultiShell,
let mut e = Encoder::new();
resolve.encode(&mut e).unwrap();
- let out = toml::Table(e.toml).to_string();
+ let out = rstoml::Table(e.toml).to_string();
let loc = pkg.get_root().join("Cargo.lock");
try!(File::create(&loc).write_str(out.as_slice()));
Ok(())
}
+
+pub fn update_lockfile(manifest_path: &Path,
+ shell: &mut MultiShell,
+ to_update: Option<String>) -> CargoResult<()> {
+ let mut source = PathSource::for_path(&manifest_path.dir_path());
+ try!(source.update());
+ let package = try!(source.get_root_package());
+
+ let lockfile = package.get_root().join("Cargo.lock");
+ let source_id = package.get_package_id().get_source_id();
+ let resolve = match try!(load_lockfile(&lockfile, source_id)) {
+ Some(resolve) => resolve,
+ None => return Err(human("A Cargo.lock must exist before it is updated"))
+ };
+
+ let mut config = try!(Config::new(shell, true, None, None));
+ let mut registry = PackageRegistry::new(&mut config);
+
+ let sources = match to_update {
+ Some(name) => {
+ let mut to_avoid = HashSet::new();
+ match resolve.deps(package.get_package_id()) {
+ Some(deps) => {
+ for dep in deps.filter(|d| d.get_name() == name.as_slice()) {
+ fill_with_deps(&resolve, dep, &mut to_avoid);
+ }
+ }
+ None => {}
+ }
+ resolve.iter().filter(|pkgid| !to_avoid.contains(pkgid))
+ .map(|pkgid| pkgid.get_source_id().clone()).collect()
+ }
+ None => package.get_source_ids(),
+ };
+ try!(registry.add_sources(sources));
+
+ let resolve = try!(resolver::resolve(package.get_package_id(),
+ package.get_dependencies(),
+ &mut registry));
+
+ try!(write_resolve(&package, &resolve));
+ return Ok(());
+
+ fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
+ set: &mut HashSet<&'a PackageId>) {
+ if !set.insert(dep) { return }
+ match resolve.deps(dep) {
+ Some(mut deps) => {
+ for dep in deps {
+ fill_with_deps(resolve, dep, set);
+ }
+ }
+ None => {}
+ }
+ }
+}
+
+pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
+ // If there is no lockfile, return none.
+ let mut f = match File::open(path) {
+ Ok(f) => f,
+ Err(_) => return Ok(None)
+ };
+
+ let s = try!(f.read_to_string());
+
+ let table = rstoml::Table(try!(toml::parse(s.as_slice(), path)));
+ let mut d = rstoml::Decoder::new(table);
+ let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
+ Ok(Some(try!(v.to_resolve(sid))))
+}
pub use self::cargo_new::{new, NewOptions};
pub use self::cargo_doc::{doc, DocOptions};
pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
+pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
mod cargo_clean;
mod cargo_compile;
self.reference.as_slice());
let should_update = self.config.update_remotes() || actual_rev.is_err();
- let repo = if should_update {
+ let (repo, actual_rev) = if should_update {
try!(self.config.shell().status("Updating",
format!("git repository `{}`", self.remote.get_location())));
log!(5, "updating git source `{}`", self.remote);
- try!(self.remote.checkout(&self.db_path))
+ let repo = try!(self.remote.checkout(&self.db_path));
+ let rev = try!(repo.rev_for(self.reference.as_slice()));
+ (repo, rev)
} else {
- self.remote.db_at(&self.db_path)
- };
- let actual_rev = match actual_rev {
- Ok(rev) => rev,
- Err(..) => try!(repo.rev_for(self.reference.as_slice())),
+ (self.remote.db_at(&self.db_path), actual_rev.unwrap())
};
try!(repo.copy_to(actual_rev.clone(), &self.checkout_path));
-use std::io::{fs, File};
+use std::io::File;
use support::{ProjectBuilder, ResultTest, project, execs, main_file, paths};
use support::{cargo_dir};
FRESH, git_project.root().display(),
FRESH, p.root().display())));
- assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
- execs().with_stdout(format!("{} git repository `file:{}`\n\
- {} bar v0.5.0 (file:{}#[..])\n\
+ assert_that(p.process(cargo_dir().join("cargo-update")),
+ execs().with_stdout(format!("{} git repository `file:{}`",
+ UPDATING,
+ git_project.root().display())));
+
+ assert_that(p.process(cargo_dir().join("cargo-build")),
+ execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
{} foo v0.5.0 (file:{})\n",
- UPDATING, git_project.root().display(),
FRESH, git_project.root().display(),
FRESH, p.root().display())));
git_project.process("git").args(["commit", "-m", "test"]).exec_with_output()
.assert();
- assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
- execs().with_stdout(format!("{} git repository `file:{}`\n\
- {} bar v0.5.0 (file:{}#[..])\n\
+ println!("compile after commit");
+ assert_that(p.process(cargo_dir().join("cargo-build")),
+ execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
{} foo v0.5.0 (file:{})\n",
- UPDATING, git_project.root().display(),
FRESH, git_project.root().display(),
FRESH, p.root().display())));
- println!("one last time");
-
- // Remove the lockfile and make sure that we update
- fs::unlink(&p.root().join("Cargo.lock")).assert();
- assert_that(p.process(cargo_dir().join("cargo-build")).arg("-u"),
- execs().with_stdout(format!("{} git repository `file:{}`\n\
- {} bar v0.5.0 (file:{}#[..])\n\
+ // Update the dependency and carry on!
+ assert_that(p.process(cargo_dir().join("cargo-update")),
+ execs().with_stdout(format!("{} git repository `file:{}`",
+ UPDATING,
+ git_project.root().display())));
+ println!("going for the last compile");
+ assert_that(p.process(cargo_dir().join("cargo-build")),
+ execs().with_stdout(format!("{} bar v0.5.0 (file:{}#[..])\n\
{} foo v0.5.0 (file:{})\n",
- UPDATING, git_project.root().display(),
COMPILING, git_project.root().display(),
COMPILING, p.root().display())));
})